﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace CodeIn.Modules.Graph.Elements {
	public class DataFlowGraph {
		public DataFlowNode[] Nodes { get { return nodes.ToArray(); } }
		public DataFlowNode[] Roots { get { return roots.ToArray(); } }
		public DataFlowNode[] Sinks { get { return sinks.ToArray(); } }

		private IList<DataFlowNode> nodes;
		private IList<DataFlowNode> roots;
		private IList<DataFlowNode> sinks;
		private IDictionary<DataFlowNode, IList<DataFlowNode>> parents;
		private IDictionary<DataFlowNode, IList<DataFlowNode>> children;

		public DataFlowGraph() {
			nodes = new List<DataFlowNode>();
			roots = new List<DataFlowNode>();
			sinks = new List<DataFlowNode>();
			parents = new Dictionary<DataFlowNode, IList<DataFlowNode>>();
			children = new Dictionary<DataFlowNode, IList<DataFlowNode>>();
		}

		public void Add(DataFlowNode node) {
			if (!nodes.Contains(node)) {
				nodes.Add(node);
				parents.Add(node, new List<DataFlowNode>());
				children.Add(node, new List<DataFlowNode>());
			}
		}

		public void Remove(DataFlowNode node) {
			nodes.Remove(node);
			parents.Remove(node);
			children.Remove(node);

			var nodeParents = GetParents(node);
			var nodeChildren = GetChildren(node);

			foreach (var parent in nodeParents)
				while (children[parent].Contains(node))
					children[parent].Remove(node);

			foreach (var child in nodeChildren)
				while (parents[child].Contains(node))
					parents[child].Remove(node);
		}

		public bool Contains(DataFlowNode node) {
			return nodes.Contains(node);
		}

		public DataFlowNode[] GetParents(DataFlowNode node) {
			var nodeParents = parents[node];
			return nodeParents.ToArray();
		}

		public DataFlowNode[] GetChildren(DataFlowNode node) {
			var nodeChildren = children[node];
			return nodeChildren.ToArray();
		}

		public void CreateLink(DataFlowNode parent, DataFlowNode child) {
			parents[child].Add(parent);
			children[parent].Add(child);
		}

		public int GetLinkCount(DataFlowNode parent, DataFlowNode child) {
			int childrenCount = GetChildren(parent).Count(n => n == child);
			return childrenCount;
		}
	}
}
